/*
 * CardCopierModel.java
 *
 * Created on 15 April 2007, 14:34
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package org.cardcopier;

import java.io.File;
import java.io.IOException;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import org.apache.log4j.Logger;
import org.cardcopier.file.CaseInsensitiveFileLocation;
import org.cardcopier.file.FileLocation;
import org.cardcopier.file.FileLocationComparator;
import org.cardcopier.file.FileLocationFactory;
import org.cardcopier.file.FileState;
import org.cardcopier.file.FileUtils;
import org.cardcopier.file.NameFormatter;

/**
 *
 * @author Mark
 */
public class CardCopierModel {

    private static final Logger LOGGER = Logger.getLogger(CardCopierModel.class);

    private final List<CardCopierModelListener> listeners = new CopyOnWriteArrayList<CardCopierModelListener>();

    private final ApplicationConfig applicationConfig;
    private final FileLocationFactory fileLocationFactory;
    private final FileUtils fileUtils = new FileUtils();

    private FileLocation sourceDir;
    private File destinationBaseDir;
    private NameFormatter destinationSubDirNameFormatter;
    private String event = "Event";
    private Date eventDate = new Date();
    private String messageText = null;
    private long spaceAvailableInDestination = -1;
    
    /** Creates a new instance of CardCopierModel */
    public CardCopierModel(ApplicationConfig applicationConfig) {
        this.applicationConfig = applicationConfig;
        this.fileLocationFactory = new FileLocationFactory(applicationConfig.getFileExtensionsToCopy());
        this.sourceDir = fileLocationFactory.createFileLocation(new File(applicationConfig.getSourceDirName()));
        this.destinationBaseDir = new File(applicationConfig.getDestinationDirName());
        this.destinationSubDirNameFormatter = new NameFormatter(applicationConfig.getDestinationSubDirFormat());
        this.event = applicationConfig.getEvent();
    }

    public ApplicationConfig getApplicationConfig() {
        applicationConfig.setDestinationDirName(destinationBaseDir.getAbsolutePath());
        applicationConfig.setDestinationSubDirFormat(destinationSubDirNameFormatter.getNamePattern());
        applicationConfig.setSourceDirName(sourceDir.getDirectory().getAbsolutePath());
        applicationConfig.setEvent(event);
        return applicationConfig;
    }
    
    public FileLocationFactory getFileLocationFactory() {
        return fileLocationFactory;
    }

    public FileLocation getFullDestinationDir() {
        String subDir = destinationSubDirNameFormatter.formatName(eventDate, event);
        return fileLocationFactory.createFileLocation(new File(destinationBaseDir, subDir));
    }
    
    public File getDestinationBaseDir() {
        return destinationBaseDir;
    }
    
    private void calculateSpaceAvailableInDestination() {
        try {
            spaceAvailableInDestination = fileUtils.spaceAvailableInBytes(destinationBaseDir);
        } catch (IOException e) {
            LOGGER.error("Failed to calculate space available in destination with ", e);
            spaceAvailableInDestination = -1;
        }        
    }
    
    public FileLocation getSourceDirectory() {
        return sourceDir;
    }
    
    public String getEvent() {
        return event;
    }
    
    public Date getEventDate() {
        return eventDate;
    }

    public String getMessageText() {
        return messageText;
    }
    
    public long getSpaceAvailableInDestination() {
        return spaceAvailableInDestination;
    }
    
    public void setMessageText(String errorText) {
        this.messageText = errorText;
        fireMessageTextChanged();
    }

    public boolean getDeleteSourceFileAfterCopy() {
        return applicationConfig.getDeleteSourceFileAfterCopy();
    }

    public void setDeleteSourceFileAfterCopy(Boolean value) {
        applicationConfig.setDeleteSourceFileAfterCopy(value);
    }

    public void setPathDetails(Date eventDate, String event, FileLocation sourceDir, File destinationBaseDir) {
//        if (!this.sourceDir.equals(sourceDir)) {
            this.sourceDir = sourceDir;
            this.notifyOfSourceLocationChange();
//        }

//        boolean destinationChanged = false;
//        if (!this.destinationBaseDir.equals(destinationBaseDir)) {
            this.destinationBaseDir = destinationBaseDir;
            calculateSpaceAvailableInDestination();
//            destinationChanged = true;
//        }

//        if (!this.event.equals(event)) {
            this.event = event;
//            destinationChanged = true;
//        }
        
//        if (!this.eventDate.equals(eventDate)) {
            this.eventDate = eventDate;
//            destinationChanged = true;
//        }
        
//        if (destinationChanged) {
            notifyOfDestinationChange();
//        }
    }
    
    public List<File> getSourceFiles() {
        return sourceDir.getFiles();
    }
    
    public List<FileState> getFileStates() {
        FileLocation destination = getFullDestinationDir();
        FileLocationComparator state = new FileLocationComparator(sourceDir, destination);
        List<FileState> fileStates = state.listFiles(new Comparator<File>() {
                public int compare(File o1, File o2) {
                        return o1.getName().compareTo(o2.getName());
                }	
        });
        return fileStates;
    }
    
    public void notifyOfSourceLocationChange() {
        sourceDir.refresh();
        fireSourceLocationChanged();
    }

    public void notifyOfDestinationChange() {
        fireDestinationLocationChanged();
    }
    
    public void addCardCopierModelListener(CardCopierModelListener listener) {
        listeners.add(listener);
    }
    
    public void removeCardCopierModelListener(CardCopierModelListener listener) {
        listeners.remove(listener);
    }
    
    private void fireSourceLocationChanged() {
        for (CardCopierModelListener listener : listeners) {
            listener.sourceLocationChanged(this);
        }
    }

    private void fireDestinationLocationChanged() {
        for (CardCopierModelListener listener : listeners) {
            listener.destinationLocationChanged(this);
        }
    }
    
    private void fireMessageTextChanged() {
        for (CardCopierModelListener listener : listeners) {
            listener.messageTextChanged(this);
        }
    }
}
